/**
 * 俄罗斯方块的DEMO
 */

( function( ){
	// region 库

	var Box = Z.element.Box;
	var Label = Z.element.Label;

	// region 工具

	// 数组辅助函数
	add2list = function( list , object ){
		list[list.length] = object;
	};

	// 辅助函数：循环取值
	var cycAt = function( arr , id ){
		return arr[id%arr.length];
	};

	// 循环函数
	var loop = function( total , task ){
		var p;
		for(p = 0; p<total; p++){
			task( p );
		}
	};
	var foreach = function( li , task ){
		var p;
		for(p in li){
			task( li[p] );
		}
	};

	// region 常数

	// 逻辑坐标系
	var LOGIC_WIDTH = 10;
	var LOGIC_HEIGHT = 20;

	// 砖块像素大小
	var BRIC_WIDTH = 20;
	var BRIC_HEIGHT = 20;

	// 各区域像素大小
	var GAP = 10;
	var GAME_WIDTH = LOGIC_WIDTH*BRIC_WIDTH;
	var GAME_HEIGHT = LOGIC_HEIGHT*BRIC_HEIGHT;
	var SCORE_WIDTH = 200;
	var SCORE_HEIGHT = 300;
	var TITLE_HEIGHT = 60;
	var TITLE_WIDTH = GAME_WIDTH+GAP+SCORE_WIDTH;
	var APP_WIDTH = GAP+TITLE_WIDTH+GAP;
	var APP_HEIGHT = GAP+TITLE_HEIGHT+GAP+GAME_HEIGHT+GAP;

	// 控制码
	var UP_KEY = 87;
	var DOWN_KEY = 83;
	var LEFT_KEY = 65;
	var RIGHT_KEY = 68;

	// 4块组模板
	var xy = function( x , y ){
		return {
			x: x,
			y: y
		};
	};
	B4_TMPLS = [
		// I
		[ [ xy( 1 , 0 ) , xy( 1 , 1 ) , xy( 1 , 2 ) , xy( 1 , 3 ) ] , [ xy( 0 , 1 ) , xy( 1 , 1 ) , xy( 2 , 1 ) , xy( 3 , 1 ) ] ] ,
		// J
		[
			[ xy( 1 , 0 ) , xy( 1 , 1 ) , xy( 1 , 2 ) , xy( 2 , 2 ) ] ,
			[ xy( 0 , 1 ) , xy( 1 , 1 ) , xy( 2 , 1 ) , xy( 0 , 2 ) ] ,
			[ xy( 1 , 0 ) , xy( 1 , 1 ) , xy( 1 , 2 ) , xy( 0 , 0 ) ] ,
			[ xy( 0 , 1 ) , xy( 1 , 1 ) , xy( 2 , 1 ) , xy( 2 , 0 ) ] ] ,
		// L
		[
			[ xy( 1 , 0 ) , xy( 1 , 1 ) , xy( 1 , 2 ) , xy( 0 , 2 ) ] ,
			[ xy( 0 , 1 ) , xy( 1 , 1 ) , xy( 2 , 1 ) , xy( 0 , 0 ) ] ,
			[ xy( 1 , 0 ) , xy( 1 , 1 ) , xy( 1 , 2 ) , xy( 2 , 0 ) ] ,
			[ xy( 0 , 1 ) , xy( 1 , 1 ) , xy( 2 , 1 ) , xy( 2 , 2 ) ] ] ,
		// S
		[ [ xy( 0 , 1 ) , xy( 1 , 1 ) , xy( 1 , 0 ) , xy( 2 , 0 ) ] , [ xy( 0 , 0 ) , xy( 0 , 1 ) , xy( 1 , 1 ) , xy( 1 , 2 ) ] ] ,
		// Z
		[ [ xy( 0 , 0 ) , xy( 1 , 0 ) , xy( 1 , 1 ) , xy( 2 , 1 ) ] , [ xy( 1 , 0 ) , xy( 1 , 1 ) , xy( 0 , 1 ) , xy( 0 , 2 ) ] ] ,
		// O
		[ [ xy( 0 , 0 ) , xy( 0 , 1 ) , xy( 1 , 0 ) , xy( 1 , 1 ) ] ] ,
		// T
		[
			[ xy( 0 , 1 ) , xy( 1 , 1 ) , xy( 2 , 1 ) , xy( 1 , 2 ) ] ,
			[ xy( 1 , 0 ) , xy( 1 , 1 ) , xy( 1 , 2 ) , xy( 2 , 1 ) ] ,
			[ xy( 0 , 1 ) , xy( 1 , 1 ) , xy( 2 , 1 ) , xy( 1 , 0 ) ] ,
			[ xy( 1 , 0 ) , xy( 1 , 1 ) , xy( 1 , 2 ) , xy( 0 , 1 ) ] ] ];
	// 按模板计算坐标
	var calcTetris = function( mode , direct , x , y ){
		var rst = [ ];
		foreach( cycAt( cycAt( B4_TMPLS , mode ) , direct ) , function( co ){
			add2list( rst , {
				x: x+co.x,
				y: y+co.y
			} );
		} );
		return rst;
	};

	// region 核心逻辑

	onLoad( function( body ){
		// 循环变量
		var i;
		var j;
		var k;

		// 应用程序区域
		var appA = body.area( {
			left: 100,
			top: 50,
			width: APP_WIDTH,
			height: APP_HEIGHT
		} );
		// 标题区域
		var titleA = appA.area( {
			left: GAP,
			top: GAP,
			width: TITLE_WIDTH,
			height: TITLE_HEIGHT,
			zIndex: GAP
		} );
		// 游戏区域
		var gameA = appA.area( {
			left: GAP,
			top: GAP+TITLE_HEIGHT+GAP,
			width: GAME_WIDTH,
			height: GAME_HEIGHT,
			zIndex: GAP
		} );
		// 计分板区域
		var scoreA = appA.area( {
			left: GAP+GAME_WIDTH+GAP,
			top: GAP+TITLE_HEIGHT+GAP,
			width: SCORE_WIDTH,
			height: SCORE_HEIGHT,
			zIndex: GAP
		} );

		// 应用程序背景图
		var appBG = Box( appA , {
			background_color: "#F0F0F0",
			left: 0,
			top: 0,
			width: APP_WIDTH,
			height: APP_HEIGHT,
			zIndex: GAP/2
		} );

		// 游戏背景图
		var gameBG = Box( gameA , {
			background_color: "#C0C0C0",
			border_color: "#000000",
			left: 0,
			top: 0,
			width: GAME_WIDTH,
			height: GAME_HEIGHT,
			zIndex: GAP/2
		} );

		// 砖
		var bric = function( x , y , color ){
			var br = Box( gameA , {
				background_color: color,
				border_color: "#404040",
				border_width: "1px",
				left: x*BRIC_WIDTH,
				top: y*BRIC_HEIGHT,
				width: BRIC_WIDTH-2,
				height: BRIC_HEIGHT-2,
				zIndex: GAP/2+1
			} );
			return {
				getX: function( ){
					return x;
				},
				getY: function( ){
					return y;
				},
				getColor: function( ){
					return color;
				},
				remove: function( ){
					br.remove( );
				}
			};
		};
		// 4块砖
		var buildTetris = function( mode , direct , x , y , color ){
			var rst = [ ];
			foreach( calcTetris( mode , direct , x , y ) , function( co ){
				add2list( rst , bric( co.x , co.y , color ) );
			} );
			return rst;
		};
		// 清理砖
		var clean = function( bli ){
			foreach( bli , function( b ){
				b.remove( );
			} );
		};

		// 下落记录
		var drop = {
			// 模板
			mode: 0,
			// 方向
			direct: 0,
			// 坐标
			x: 0,
			y: 0,
			// 颜色
			color: "",
			// 实体
			brics: [ ]
		};
		// 基底记录
		var base = {
			layers: [ ],
			fulls: [ ],
			rank: 0
		};
		// Tetris运动
		var go = function( op ){
			// 下一步坐标
			var next = {
				"up": {
					x: drop.x,
					y: drop.y,
					direct: drop.direct+1
				},
				"down": {
					x: drop.x,
					y: drop.y+1,
					direct: drop.direct
				},
				"left": {
					x: drop.x-1,
					y: drop.y,
					direct: drop.direct
				},
				"right": {
					x: drop.x+1,
					y: drop.y,
					direct: drop.direct
				}
			};
			// 判断是否接受
			var accepted = true;
			foreach( calcTetris( drop.mode , next[op].direct , next[op].x , next[op].y ) , function( co ){
				if(co.x<0||co.y<0||co.x>=LOGIC_WIDTH||co.y>=LOGIC_HEIGHT){
					accepted = false;
				}
				foreach( base.layers , function( l ){
					foreach( l , function( b ){
						if(co.x==b.getX( )&&co.y==b.getY( )){
							accepted = false;
						}
					} );
				} );
			} );
			// 接受则重构
			if(accepted){
				drop.x = next[op].x;
				drop.y = next[op].y;
				drop.direct = next[op].direct;
				clean( drop.brics );
				drop.brics = buildTetris( drop.mode , drop.direct , drop.x , drop.y , drop.color );
				return true;
			}
			else{
				return false;
			}
		};

		// 游戏阶段
		var STAT = {
			OVER: 0,
			DROP: 1,
			RENEW: 2,
			HIGHLIGHT: 3,
			CREDIT: 4
		};
		var stat = STAT.OVER;
		// 分数
		var score = 0;
		// 计分板
		var scoreL = Label( scoreA , {
			left: 0,
			top: 0,
			text: "",
			font_size: "36px"
		} );
		// 游戏逻辑：下落、得分、更新
		var logic = [
		// over
		function( ){

		} ,
		// drop
		function( ){
			if(!go( "down" )){
				//停止下落
				stat = STAT.CREDIT;
			}
		} ,
		// renew
		function( ){
			// 选择新块
			drop.mode = drop.mode+1;
			drop.color = "#808080";
			// 初始化位置
			drop.direct = 0;
			drop.x = LOGIC_WIDTH/2-1;
			drop.y = 0;
			// 砍掉重练
			drop.brics = buildTetris( drop.mode , drop.direct , drop.x , drop.y , drop.color );

			// 立即执行下一步
			stat = STAT.DROP;
			logic[stat]( );
		} ,
		// highlight
		function( ){
			// 加分
			var ds = 1;
			loop( base.rank , function( ){
				ds = ds*5;
			} );
			score += ds/5;
			scoreL.text( score.toString( ) );
			base.rank = 0;

			// 消除满行

			// 添加不满行
			var nls = [ ];
			foreach( base.layers , function( l ){
				if(l.length!=LOGIC_WIDTH){
					var bs = [ ];
					foreach( l , function( b ){
						add2list( bs , bric( b.getX( ) , LOGIC_HEIGHT-1-nls.length , b.getColor( ) ) );
					} );
					add2list( nls , bs );
				}
			} );
			// 清理原有砖
			clean( base.fulls );
			base.fulls = [ ];
			foreach( base.layers , function( l ){
				clean( l );
			} );
			base.layers = nls;

			// 立即执行下一步
			stat = STAT.RENEW;
			logic[stat]( );
		} ,
		// credit
		function( ){
			// 将下落块合并进积累块
			foreach( drop.brics , function( b ){
				var index = LOGIC_HEIGHT-1-b.getY( );
				base.layers[index] = base.layers[index]|| [ ];
				add2list( base.layers[index] , b );
			} );
			drop.brics = [ ];
			// 处理填满的列
			base.fulls = [ ];
			foreach( base.layers , function( l ){
				if(l.length==LOGIC_WIDTH){
					loop( LOGIC_WIDTH , function( x ){
						add2list( base.fulls , bric( x , l[0].getY( ) , "#FFFFFF" ) );
					} );
					base.rank = base.rank+1;
				}
			} );

			// 有消除则高亮
			if(base.rank>0){
				stat = STAT.HIGHLIGHT;
			}
			// 顶格则结束
			else if(base.layers.length>=LOGIC_HEIGHT){
				turn.stop( );
				alert( "game over" );
				stat = STAT.OVER;
			}
			// 否则直接新开始
			else{
				// 立即执行下一步
				stat = STAT.RENEW;
				logic[stat]( );
			}
		} ];
		// 定时逻辑
		var turn = body.Timer( function( ){
			logic[stat]( );
		} , 1000 );
		
		// 按键逻辑
		var move = {
			"left": body.Timer(function(){
				if(stat==STAT.DROP){
					go( "left" );
				}
			},50),
			"right": body.Timer(function(){
				if(stat==STAT.DROP){
					go( "right" );
				}
			},50)
		};
		body.onKeydown( function( e ){			
			switch(e.keyCode){
			case UP_KEY:
				if(stat==STAT.DROP){
					go( "up" );
				}
				break;
			case LEFT_KEY:
				move["left"].start();
				break;
			case RIGHT_KEY:
				move["right"].start();
				break;
			}
		} );
		body.onKeyup( function( e ){			
			switch(e.keyCode){
			case LEFT_KEY:
				move["left"].stop();
				break;
			case RIGHT_KEY:
				move["right"].stop();
				break;
			}
		} );
		
		// 定时加速
		var accelerater = body.Timer(function(){
			logic[stat]( );
		},50);
		//下键按住加速
		body.onKeydown( function( e ){			
			switch(e.keyCode){
			case DOWN_KEY:
				accelerater.start();
				break;
			}
		} );
		body.onKeyup( function( e ){			
			switch(e.keyCode){
			case DOWN_KEY:
				accelerater.stop();
				break;
			}
		} );

		// 重置按钮
		var btnReset = Box( titleA , {
			background_color: "#00FF00",
			border_radius: BRIC_WIDTH/2+"px",
			left: 0,
			top: 0,
			width: BRIC_WIDTH,
			height: BRIC_WIDTH,
			zIndex: GAP/2,
			onClick: function( ){
				// 停止
				turn.stop( );

				// 重置下落块
				clean( drop.brics );
				drop.brics = [ ];
				// 重置积累块
				clean( base.fulls );
				base.fulls = [ ];
				foreach( base.layers , function( l ){
					clean( l );
				} );
				base.layers = [ ];
				// 清零积分
				score = 0;
				scoreL.text( "0" );

				// 开始
				stat = STAT.RENEW;
				turn.start( );
			}
		} );
	} );
} )( );